<template>
  <transition
    :css="false"
    @before-enter="beforeEnter"
    @enter="enter"
    @after-enter="afterEnter"
    @before-leave="beforeLeave"
    @leave="leave"
    @after-leave="afterLeave"
  >
    <slot name="default"></slot>
  </transition>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'LogoTransition',
  setup() {
    const duration = 300
    const transition = `all ${duration}ms ease-in-out, opacity ${duration}ms ${duration}ms`
    const on = {
      beforeEnter(el: HTMLElement) {
        // 添加内联样式的 transition
        el.style.transition = transition
        // 内联样式的 width 初始值
        el.style.width = '0'
        // 内联样式的 margin-left 初始值
        el.style.marginLeft = '0'
        // 内联样式的 opacity 初始值
        el.style.opacity = '0'
      },
      enter(el: HTMLElement, done: () => void) {
        if (el.scrollWidth !== 0) {
          // 获取元素宽度，赋值到内联样式的 width
          // transition 使用该值做为目标值
          el.style.width = `${el.scrollWidth}px`
          // 移除内联样式的 margin-left
          // 从而使用 class 中的 margin-left 作为目标值
          el.style.marginLeft = ''
          // 移除内联样式的 opacity
          // 从而使用默认值 1
          el.style.opacity = ''
          // 等待 transition 完成，否则 transition 将立即完成，丢失过渡效果
          // 完成后后回调 done() 函数进入 after-enter 阶段
          setTimeout(() => done(), duration)
        } else {
          // 元素宽度为零
          // 移除内联样式的 width
          el.style.width = ''
          // 进入 after-enter 阶段
          done()
        }
      },
      afterEnter(el: HTMLElement) {
        // 移除内联样式的 transition
        el.style.transition = ''
        // 移除内联样式的 width
        el.style.width = ''
      },
      beforeLeave(el: HTMLElement) {
        // 添加内联样式的 transition
        el.style.transition = transition
        // 内联样式的 width 初始值
        el.style.width = `${el.scrollWidth}px`
      },
      leave(el: HTMLElement, done: () => void) {
        if (el.scrollWidth !== 0) {
          // 内联样式的 width，transition 使用该值做为目标值
          el.style.width = '0'
          // 添加内联样式的 margin-left
          // 从而使用该作为目标值
          el.style.marginLeft = '0'
          // 添加内联样式的 opacity
          // 从而使用该作为目标值
          el.style.opacity = '1'
          // 等待 transition 完成，否则 transition 将立即完成，丢失过渡效果
          // 完成后后回调 done() 函数进入 after-enter 阶段
          setTimeout(() => done(), duration)
        } else {
          // 元素宽度为零，进入 after-enter 阶段
          done()
        }
      },
      afterLeave(el: HTMLElement) {
        // 移除内联样式的 transition
        el.style.transition = ''
        // 移除内联样式的 width
        el.style.width = ''
        // 移除内联样式的 margin-left
        el.style.marginLeft = ''
        // 移除内联样式的 opacity
        el.style.opacity = ''
      }
    }

    return { ...on }
  }
})
</script>
